/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include "tester.h"
/* includes (standard library, system) ---------------------------------------*/
#include <string.h>
#include <stdio.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <cmder.h>

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (global) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/

static tester_case_t *case_table;
static unsigned int case_num;

/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static void __tester_usage(void)
{
    printf("\n");
    printf("Command: tester\n");
    printf("   info: Execute test cases.\n");
    printf(" format: tester [-l | -a | testnames]\n");
    printf("   usage:\n");
    printf("       tester\n");
    printf("           Show tester help information\n");
    printf("       tester -l\n");
    printf("           List all test cases.\n");
    printf("       tester -a\n");
    printf("           Run all test cases.\n");
    printf("       tester test1 test2 ...\n");
    printf("           Run 'test1' 'test2'\n");
    printf("\n");
}

static void __tester_statistics(void)
{
    unsigned int i;
    unsigned int totals = 0, fails = 0;

    printf("\nstatistics:\n");
    for (i = 0; i < case_num; ++i) {
        printf("%-15s: totals %2d, fails %2d\n", case_table[i].name, case_table[i].stats->totals,
               case_table[i].stats->fails);
        totals += case_table[i].stats->totals;
        fails += case_table[i].stats->fails;
    }
    printf("\n  totals: %d, fails: %d\n\n", totals, fails);
}

static void __tester_init(void)
{
    case_table = (tester_case_t *)(__section_start__(TESTER_SECTION));
    case_num = (unsigned int)(__section_end__(TESTER_SECTION) - __section_start__(TESTER_SECTION));

    case_num /= sizeof(tester_case_t);
}

static tester_case_t *__tester_match(const char *name)
{
    unsigned int i;

    for (i = 0; i < case_num; ++i) {
        if (strcmp(case_table[i].name, name) == 0) {
            return &case_table[i];
        }
    }
    return NULL;
}

static void __tester_list(void)
{
    unsigned int i;

    if (case_num == 0) {
        printf("nothing...\n");
        return;
    }

    printf("\ntest cases:\n");
    for (i = 0; i < case_num; ++i) {
        printf("   %s\n", case_table[i].name);
    }
    printf("\n  totals %d\n\n", case_num);
}

static int __tester_run(tester_case_t *caser)
{
    if (caser->setup != NULL) {
        caser->setup();
    }
    if (caser->entry != NULL) {
        caser->entry(caser);
    }
    if (caser->teardown != NULL) {
        caser->teardown();
    }
    return 0;
}

static int __tester_run_all(void)
{
    unsigned int i;

    for (i = 0; i < case_num; ++i) {
        __tester_run(&case_table[i]);
    }
    return 0;
}

static int __tester_run_some(int argc, char *argv[])
{
    int i;

    for (i = 1; i < argc; i++) {
        tester_case_t *caser = __tester_match(argv[i]);
        if (caser != NULL) {
            __tester_run(caser);
        } else {
            printf("\"%s\" testcase not found!\n", argv[1]);
        }
    }
    return 0;
}

static int __cmd_tester(cmder_t *cmder, int argc, char *argv[])
{
    __tester_init();

    if (argc > 1) {
        if (strcmp(argv[1], "-l") == 0) {
            __tester_list();
        } else if (strcmp(argv[1], "-a") == 0) {
            __tester_run_all();
            __tester_statistics();
        } else {
            __tester_run_some(argc, argv);
        }
    } else {
        __tester_usage();
    }

    return 0;
}

CMDER_CMD_DEF("tester", "execute test cases, usage: 'tester [-l | -a | testnames]'", __cmd_tester);
